//ReflectionTest.java
package com.ylaihui.reflection;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    @Test
    public void testoop(){
        //没有反射之前，符合面向对象的基本规则,私有属性、方法，类外部可不见
        Productor p = new Productor();
        p.price = 11.11;

        String s = p.showName();

        System.out.println(p.toString());
    }

    // 有了反射之后
    @Test
    public void testreflection() throws Exception {
        // 获取JVM加载类 Productor 时的对象
        Class clazz = Productor.class;
        // 获取类的构造器 public Productor(String name, double price)，并创建 Productor 的实例
        System.out.println("#1 test ************");
        Constructor cons = clazz.getConstructor(String.class, double.class);

        Object obj = cons.newInstance("Java开发实战教程", 128.00);

        Productor p = (Productor) obj;

        System.out.println(obj);
        System.out.println(p.getName() + ":" +p.getPrice());

        //通过反射调用属性,getDeclaredField可以获取所有的属性，包括私有的
        // getField 不可获取私有的属性，同理方法也是一样
        System.out.println("#2 test ************");
        Field price = clazz.getField("price");
        price.set(p, 118.00);
        System.out.println(p);

        //通过反射调用方法, showName方法有重载的情况，需要指定形参的类型
        System.out.println("#3 test ************");
        Method showName = clazz.getDeclaredMethod("showName", String.class);
        Object str = showName.invoke(p, "SpringBoot开发实战");
        System.out.println(str);
        System.out.println(p);

        // 调用重载的方法，获取和调用时，传入的参数需要指明
        System.out.println("#4 test ************");
        Method showName1 = clazz.getDeclaredMethod("showInfo");
        showName1.setAccessible(true);  // 默认false IllegalAccessException
        Object invoke = showName1.invoke(p);

        // 通过反射，调用私有的结构
        // 构造器
        System.out.println("#5 test ************");
        Class aClass = Productor.class;
        Constructor cons1 = aClass.getDeclaredConstructor(String.class);
        cons1.setAccessible(true);
        Object obj1 = cons1.newInstance("算法实战");
        System.out.println(obj1);

        // 属性和方法与上类似，只是需要使用 getDeclaredXxx方法，并 setAccessible(true)
        //...
    }
}
